package base.reflect.annotation;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Proxy;
import java.util.LinkedList;

public class ObjectFactory {

    @SuppressWarnings("all")
    public static <T> T newInstance(Class<T> clazz) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        var annotations = clazz.getAnnotations();
        var aspects = new LinkedList<IAspect>();

        for (var annotation : annotations) {
            if (annotation instanceof Aspect) {
                var type = ((Aspect) annotation).type();
                var aspect = (IAspect) (type.getConstructor().newInstance());
                aspects.push(aspect);
            }
        }
        var instance = clazz.getConstructor().newInstance();
        return (T) Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), (proxy, method, args) -> {
            aspects.forEach(aspect -> aspect.before());
            var result = method.invoke(instance);
            aspects.forEach(aspect -> aspect.after());
            return result;
        });
    }
}
